SPB Git
5.1 KB · 70 lines tsx
1import Link from "next/link";2import { ArrowRight, Search } from "lucide-react";3import { getLocale } from "@/lib/i18n/server";4import { fmtDate, href, t } from "@/lib/i18n";5import { domainsWithCounts, graph, listPapers, stats } from "@/lib/papers/queries";6import { PaperCard, PaperRow } from "@/components/paper-items";7import { StatTiles } from "@/components/stat-tiles";8import { Constellation, type GEdge, type GNode } from "@/components/constellation";9export const revalidate = 300;1011export default async function Home() {12  const locale = await getLocale(); const d = t(locale);13  const [s, featured, latest, domains, g] = await Promise.all([stats(), listPapers({ featured: true, sort: "recent", perPage: 4 }), listPapers({ sort: "revised", perPage: 6 }), domainsWithCounts(), graph(["topic", "method", "dataset", "author", "semantic", "curated"])]);14  const featuredItems = [...featured.items].sort((a, b) => (a.featured_rank ?? 99) - (b.featured_rank ?? 99));15  return (16    <>17      <section className="border-b border-line bg-bg-2/60">18        <div className="container py-14 sm:py-20 grid gap-8 lg:grid-cols-[1.4fr_1fr] items-end">19          <div>20            <p className="kicker mb-3">{d.site.secondary} · {d.site.affiliation}</p>21            <h1 className="text-4xl sm:text-5xl leading-[1.08] text-fg">{d.home.heroTitle}</h1>22            <p className="mt-5 text-lg text-fg-2 max-w-2xl leading-relaxed">{d.home.heroLead}</p>23            <form action={href(locale, "/search")} method="get" role="search" className="mt-7 flex gap-2 max-w-2xl">24              <label htmlFor="home-q" className="sr-only">{d.nav.search}</label>25              <input id="home-q" name="q" className="input" placeholder={d.home.searchPlaceholder} autoComplete="off" />26              <button type="submit" className="btn btn-primary shrink-0"><Search size={16} aria-hidden /> <span className="hidden sm:inline">{d.search.go}</span></button>27            </form>28            <div className="mt-5 flex flex-wrap gap-2">29              <Link href={href(locale, "/papers")} className="btn btn-primary no-underline">{d.home.explore} <ArrowRight size={16} aria-hidden /></Link>30              <Link href={href(locale, "/topics")} className="btn no-underline">{d.home.browseTopics}</Link>31            </div>32          </div>33          <div className="text-sm text-fg-3 lg:text-right"><p className="serif text-fg text-lg italic">{d.site.tagline}</p></div>34        </div>35      </section>3637      <section className="container py-12">38        <div className="flex items-end justify-between gap-4 mb-5"><div><h2 className="text-2xl">{d.home.stats}</h2><p className="meta mt-1">{d.home.statsLead}</p></div></div>39        <StatTiles s={s} locale={locale} />40      </section>4142      {featuredItems.length > 0 && (43        <section className="container py-6">44          <div className="flex items-end justify-between gap-4 mb-5"><div><h2 className="text-2xl">{d.home.featured}</h2><p className="meta mt-1">{d.home.featuredLead}</p></div><Link href={href(locale, "/papers")} className="text-sm text-navy no-underline hover:underline whitespace-nowrap">{d.home.viewAll} →</Link></div>45          <div className="grid gap-4 md:grid-cols-2">{featuredItems.map((p) => <PaperCard key={p.id} p={p} locale={locale} />)}</div>46        </section>47      )}4849      <section className="container py-10 grid gap-10 lg:grid-cols-[1.5fr_1fr]">50        <div>51          <div className="flex items-end justify-between gap-4 mb-2"><div><h2 className="text-2xl">{d.home.latest}</h2><p className="meta mt-1">{d.home.latestLead}</p></div><Link href={href(locale, "/papers?sort=revised")} className="text-sm text-navy no-underline hover:underline whitespace-nowrap">{d.home.viewAll} →</Link></div>52          <div className="card px-5">{latest.items.map((p) => <PaperRow key={p.id} p={p} locale={locale} compact />)}</div>53        </div>54        <div>55          <h2 className="text-2xl">{d.home.domains}</h2><p className="meta mt-1 mb-4">{d.home.domainsLead}</p>56          <ul className="grid gap-2">57            {domains.map((dm) => <li key={dm.slug}><Link href={href(locale, `/topics/${dm.slug}`)} className="card px-4 py-3 flex items-center gap-3 no-underline hover:shadow-[var(--shadow-lift)] transition-shadow"><span className="w-2.5 h-2.5 rounded-full shrink-0" style={{ background: dm.accent ?? "var(--navy)" }} /><span className="flex-1 text-fg">{locale === "fr" ? dm.name_fr : dm.name_en}</span><span className="text-xs text-fg-3 font-mono">{dm.n}</span></Link></li>)}58          </ul>59        </div>60      </section>6162      <section className="container py-10">63        <div className="flex items-end justify-between gap-4 mb-5"><div><h2 className="text-2xl">{d.home.constellation}</h2><p className="meta mt-1 max-w-3xl">{d.home.constellationLead}</p></div><Link href={href(locale, "/research-map")} className="text-sm text-navy no-underline hover:underline whitespace-nowrap">{d.home.openMap} →</Link></div>64        <Constellation locale={locale} nodes={g.nodes as unknown as GNode[]} edges={g.edges as unknown as GEdge[]} compact />65      </section>66      <p className="container text-xs text-fg-3 pb-4">{d.stats.latest}: {s.latest ? fmtDate(locale, s.latest, "month") : "—"}</p>67    </>68  );69}70
Files · main
Menu

Theme